package org.teamh.connection;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.Semaphore;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.teamh.game.Start;
import org.teamh.game.repository.MapRepository;

public class MapDownload {

	private Start start;
	private ZipInputStream zipIn;
	private File map;
	private File picture;
	private FileOutputStream fout;
	private String name;
	
	private Semaphore mapDownload;
	
	private boolean downloaded;

	public MapDownload(Start start) {
		this.start = start;
		mapDownload = new Semaphore(1, true);
	}
	
	/**
	 * Asks to download a map. It can only be downloaded one map at any time. To
	 * ensure this, a semaphore is used. If a map is already downloading, this
	 * method will block until it is finished.
	 * 
	 * @param map
	 */
	public void downloadMap(String map) {
		if(MapRepository.contains(map)) {
			this.map = MapRepository.getMap(map);
			picture = MapRepository.getPicture(map);
			
			downloaded = true;
		} else {
			
			try {
				mapDownload.acquire();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			this.name = map;
			start.getConnection().sendMessage("DOWNLOAD MAP " + map);
		}
	}
	
	/**
	 * This method returns true only once, if the map was directly downloaded. Else otherwise. 
	 * @return
	 */
	public boolean isDownloaded() {
		boolean downloaded = this.downloaded;
		this.downloaded = false;
		
		return downloaded;
	}

	/**
	 * This method receives a map from the server and extracts it on the local
	 * harddrive. It can then be accessed view the map download class.
	 * 
	 * @param length
	 */
	public void map(int length) {
		byte[] array = new byte[length];
		
		try {
			
			start.getConnection().getInputStream().readFully(array);
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		ByteArrayInputStream bin = new ByteArrayInputStream(array);

		try {
			zipIn = new ZipInputStream(bin);

			ZipEntry ze = null;

			while ((ze = zipIn.getNextEntry()) != null) {
				if (ze.getName().contains(".jpg")) {
					picture = File.createTempFile("picture", ".jpg");
					fout = new FileOutputStream(picture);
				} else {
					map = File.createTempFile("map", ".map");
					fout = new FileOutputStream(map);
				}
				for (int c = zipIn.read(); c != -1; c = zipIn.read()) {
					fout.write(c);
				}
				zipIn.closeEntry();
				fout.flush();
				fout.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		downloaded = true;
		
		MapRepository.put(name, picture, map);
		
		mapDownload.release();
	}

	public String getPath() {
		return picture.getAbsolutePath();
	}

	public File getPicture() {
		return picture;
	}
	
	public File getMap() {
		return map;
	}
	
	/**
	 * This method does busy waiting, until the map is loaded. 
	 */
	public void waitForDownload() {
		while(!isDownloaded()) {
			try {
				Thread.sleep(20);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
